/**
 * a class representing an ordered group of shapes.
 * @author Matan Monitz, Nadav Cohen 
 *
 */
public class ShapesContainer {
	private Shape[] shapesArray; 
	public static final int INIT_SIZE=10; 
	public static final int RESIZE=10; 
	private void enlarge()
	{
		Shape[] temp = new Shape[shapesArray.length+RESIZE];
		for(int i=0;i<shapesArray.length;i++) //loop through the array and copy the shapes to the new enlarged array
			temp[i]=shapesArray[i];
		shapesArray=temp;
	}
	/**
	 * a constructor for ShapesContainer
	 * initializes the container array to the initial size: {@value #INIT_SIZE} 
	 */
	public ShapesContainer()
	{
		shapesArray=new Shape[INIT_SIZE];
	}
	/**
	 * returns the shape in the i place in the container array
	 * @param i the index of the required shape, must be bigger then 0 and smaller then the number of shapes currently in the array (use {@link #getShapesNum()})
	 * @return a pointer to the required shape. you must cast it to the required shape class
	 */
	public Shape getShape(int i) 
	{
		if(i>=0 && i<shapesArray.length && shapesArray[i]!=null)
			return shapesArray[i];
		else
			throw new RuntimeException("no shape in " +i+ " location");
	}
	/**
	 * a copy constructor for ShapesContainer, uses shallow copy
	 * @param other an instance of ShapesContainer, must be initialized
	 */
	public ShapesContainer(ShapesContainer other)
	{
		shapesArray=new Shape[INIT_SIZE];
		if(other == null)
			throw new RuntimeException("input object uninitialized");
		double shapesNum = other.getShapesNum();
		while(this.shapesArray.length<shapesNum)
			this.enlarge();
		for(int i=0;i<shapesNum;i++)//loop through the shapes in the object to be copied and copy them to new array
			shapesArray[i]=other.getShape(i);
	}
	/**
	 * adds a shape to the array by shallow copying it's address <br> it will be placed in a position based on its area in descending order
	 * @param newShape an instance of a shape object, it must be initialized 
	 * @return true if the shape was added and false if the instance of the object is already in the container
	 */
	public boolean add(Shape newShape)
	{
		boolean done=false;
		if(newShape == null)
			throw new RuntimeException("input object uninitialized");
		double area = newShape.getArea(); //get the area of the new shape
		for(int i=0;!done && i<shapesArray.length;i++) //loop through the current array 
		{
			if(shapesArray[i]==newShape) //if the shape is found in the current array don't add it 
				return false;
			if(shapesArray[i]==null || shapesArray[i].getArea()<area) //find a smaller shape then the new shape to put in front (or an empty slot if it's smaller) 
			{
				if(shapesArray[shapesArray.length-1]!=null)//check if we need to enlarge to accommodate the new shape
					this.enlarge();
				for(int j=shapesArray.length-1;j>i ;j--) //move all the shapes (from the end up to the slot we found for the new shape) one slot to the right 
				{
					shapesArray[j]=shapesArray[j-1];
				}
				shapesArray[i]=newShape;//place the new shape in it's place
				done=true;
			}
		}
		return done;
		
		
	}
	/**
	 * get the number of shapes in the container
	 * @return the amount of initialized shapes in the container
	 */
	public int getShapesNum()
	{
		for(int i=0;i<shapesArray.length;i++) 
		{
			if(shapesArray[i]==null)
				return i;
		}
		return this.shapesArray.length;
	}
	/**
	 * remove an instance of a shape from the array
	 * @param toRemove the instance to be removed, it must not be null
	 * @return true if the shape was removed false if the shape was not found in the container
	 */
	public boolean remove(Shape toRemove)
	{
		boolean done=false;
		if(toRemove == null)
			throw new RuntimeException("input object uninitialized");
		for(int i=0;!done && i<shapesArray.length;i++) //loop through the current container
		{
			if(shapesArray[i]==toRemove) //look for the shape we need to remove
				{
				for(int j=i;shapesArray[j]!=null && j<shapesArray.length;j++) //move all the shapes (starting from the shape we need to remove) on slot to the left
					{
						shapesArray[j]=shapesArray[j+1];
					}
					done=true;
				}
		}
		return done;
	}
	/**
	 * remove the shape in 
	 * @param i the index of the required shape to be removed.<br> must be bigger then 0 and smaller then the number of shapes currently in the array (use {@link #getShapesNum()})
	 * @return true
	 */
	public boolean remove(int i)
	{
		if(i<0 || i>=shapesArray.length || shapesArray[i]==null) //checks if the index is within the range of current shapes
			throw new RuntimeException("parameter incorrect, less then "+i+" shapes");
		for(int j=i;j<shapesArray.length && shapesArray[j]!=null;j++) //loop through the array starting from the index to remove and move all shapes one slot to the left
		{
				shapesArray[j]=shapesArray[j+1];
		}
			
		return true;
	}
	/**
	 * calculates the total sum of all of the shape's areas by calling each instance's getArea
	 * @return sum of all areas
	 */
	public double sumArea()
	{
		double sum=0;
		for(int i=0;i<this.getShapesNum();i++) 
			sum=sum+shapesArray[i].getArea();
		return sum;
	}
	/**
	 * calculates the total sum of all of the shape's perimeters by calling each instance's getArea
	 * @return sum of all perimeters
	 */
	public double sumPerimeter()
	{
		double sum=0;
		for(int i=0;i<this.getShapesNum();i++)
			sum=sum+shapesArray[i].getPerimeter();
		return sum;
	}
	/**
	 * moves all shape's points
	 * @param p an instance of Point, must be initialized
	 */
	public void move(Point p)
	{
		for(int i=0;i<shapesArray.length;i++)
			shapesArray[i].move(p);
	}
}
